﻿using System.Collections.Generic;
using RaptorEngine.Components;
using Microsoft.Xna.Framework;
using RaptorEngine.Threads;

namespace RaptorEngine
{
	public class Entity
	{
		private Dictionary<ComponentType, Component> _components;
        public Dictionary<ComponentType, Component> Components { get { return _components; } }

        /// <summary>Used to determine whether a WorldMatrix component
        /// (scale, rotation, translation) has been changed</summary>
		private bool _dirty = false;
		private bool _networkable;

        // Used to see wich of the components that are able to sync over the network.
	    public Dictionary<string, Component> NetworkSyncComponents { get; set; }


        public bool Networkable { get { return _networkable; } set { _networkable = value; } }

		private int _id;
        public int Id { get { return _id; } set { _id = value; } }

        /// <summary>The data used by the update-thread</summary>
		private Vector3 _position = Vector3.Zero;
        /// <summary>Directly sets the data used by the update-thread
        /// and sends a change message to update the render-thread</summary>
		public Vector3 Position
		{
			get { return _position; }
			set { _position = value;
				_dirty = true;
			}
		}

	    private float _orientation;
	    public float Orientation
	    {
            get { return _orientation; }
            set { _orientation = value; }
	    }

        /// <summary>The data used by the update-thread</summary>
		private Quaternion _rotation = Quaternion.Identity;
        /// <summary>Directly sets the data used by the update-thread
        /// and sends a change message to update the render-thread</summary>
		public Quaternion Rotation { 
			get { return _rotation; } 
			set { _rotation = value;
				_dirty = true;
			} 
		}

        /// <summary>The data used by the update-thread</summary>
		private float _scale = 1;
        /// <summary>Directly sets the data used by the update-thread
        /// and sends a change message to update the render-thread</summary>
		public float Scale { 
			get { return _scale; } 
			set { _scale = value;
				_dirty = true;
			} 
		}

        /// <summary>The data used by the draw-thread made from
        /// the scale, rotation and translation that the update-thread uses</summary>
		public Matrix WorldMatrix
		{
			get
			{
				return Matrix.CreateScale(_scale) * Matrix.CreateFromQuaternion(_rotation) * Matrix.CreateTranslation(_position);
			}
		}

        public Entity()
        {
            _id = GameEngine.Instance.GetNextId();
            _components = new Dictionary<ComponentType, Component>();
        }

        public Entity(Vector3 pos)
            :this()
        {
            Position = pos;
        }
        public Entity(Vector2 pos)
            :this()
        {
            Position = new Vector3(pos.X,pos.Y,0);
        }

        public void AddComponent(Component component)
        {
            if (HasComponent(component.ComponentType))
                RemoveComponent(component.ComponentType);

            _components.Add(component.ComponentType, component);
        }

		public void RemoveComponent(ComponentType type)
		{
			_components.Remove(type);
		}

        public bool HasComponent(ComponentType componentType)
        {
            return _components.ContainsKey(componentType);
        }

        public Component GetComponent(ComponentType type)
        {
            if (_components.ContainsKey(type))
            {
                return _components[type];
            }
            return null;
        }

	    internal void SendChangeMessage()
		{
			if (_dirty)
			{
				GameEngine.Instance.UpdateBuffer.Add(new ChangeMessage()
					{
						MessageType = ChangeMessageType.UpdateWorldMatrix, ID = Id, WorldMatrix = WorldMatrix
                        
					});
				_dirty = false;
			}
		}

	}
}
